package org.zjt.platform.springbootreactivedemo.config;

import org.springframework.boot.actuate.autoconfigure.security.reactive.EndpointRequest;
import org.zjt.platform.springbootreactivedemo.service.impl.ReactiveUserDetailsServiceImpl;
import org.zjt.platform.springbootreactivedemo.util.MD5Util;
import org.springframework.boot.autoconfigure.security.reactive.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;

import java.util.Objects;

import static org.springframework.security.config.web.server.ServerHttpSecurity.http;


/**
 * @author <a href="juntao.zhang@qq.com">juntao.zhang</a>
 * @Description:
 * @Package org.zjt.platform.springbootreactivedemo.config
 * @date 2018/3/15 13:47
 * @see
 */
@Configuration
@EnableGlobalMethodSecurity
public class ReactiveSecurityConfiguration  {

    /**
     * 配置 authenticationManager
     * @param reactiveAuthenticationManager
     * @return
     */
    @Scope("prototype")
    @Bean
    public ServerHttpSecurity httpSecurity(ReactiveAuthenticationManager reactiveAuthenticationManager) {
        return http()
                .authenticationManager(reactiveAuthenticationManager)
                .headers().and()
                .logout().and();
    }

    /**
     * 配置URL权限
     * @param httpSecurity
     * @return
     */
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity httpSecurity) {
        httpSecurity.csrf().disable()           //防止重复token
                .authorizeExchange()
                .matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                .pathMatchers("/", "/bar")
                .authenticated()
                .pathMatchers("/favicon.ico").permitAll()
                .pathMatchers("/actuator/**").permitAll()
                //  /person/*,/druid/* 必须权限为  ADMIN
                .pathMatchers("/person/*","/druid/*").hasAuthority("ADMIN")
                //  /person/* ,/persons  角色必须为 BOSS
                .pathMatchers("/person/*","/persons","/druid/*").hasRole("BOSS")
                .and()
                .formLogin();


        //httpSecurity.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll();

        return httpSecurity.build();
    }


    /**
     * 配置密码加密、JDBC数据源配置
     * @param reactiveUserDetailsService
     * @return
     */
    @Bean
    public ReactiveAuthenticationManager reactiveAuthenticationManager(ReactiveUserDetailsServiceImpl reactiveUserDetailsService) {
        UserDetailsRepositoryReactiveAuthenticationManager userDetailsRepositoryReactiveAuthenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(reactiveUserDetailsService);
        userDetailsRepositoryReactiveAuthenticationManager.setPasswordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                if (Objects.isNull(charSequence) || charSequence.length() < 1)
                    throw new IllegalArgumentException("密码长度异常");
                return MD5Util.encode(String.valueOf(charSequence));
            }
            @Override
            public boolean matches(CharSequence charSequence, String s) {
                if (Objects.isNull(charSequence) || charSequence.length() < 1)
                    throw new IllegalArgumentException("密码长度异常");
                return Objects.equals(MD5Util.encode(String.valueOf(charSequence)),s);
            }
        });
        return userDetailsRepositoryReactiveAuthenticationManager;
    }
}
